package com.phamkhanh.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

public class MainFrame extends javax.swing.JFrame {

    private Config config;
    private Population population;
    
    private boolean isRunning;  // xác định đang tiến hóa không
    private boolean isSolving; // Xác định đang giải hay không
    
    
    private long startTime;
    private long realTime;
    private long offset = 0;
    
    private float threshold = 10;
    private boolean doxet = true;
    private boolean nuocrut = false;
    
    public MainFrame() {
        this.config = new Config();
        initComponents();
        initFrame();
    }

    private void initFrame() {
        startTime = 0;
        realTime = 0;
        offset = 0;
        isRunning = false;
        isSolving = false;
        txtMaxAge.setText(config.getMaxAge() + "");
        txtPopulation.setText(config.getPopulation() + "");
        txtPc.setText(config.getPc() + "");
        txtPm.setText(config.getPm() + "");
        cbbChooseCrossOver.setSelectedIndex(config.getTypeCrossOver());
        cbbChooseMutation.setSelectedIndex(config.getTypeMutation());
        pgbPercent.setMinimum(0);
        pgbPercent.setMaximum(config.getMaxAge());
        pgbPercent.setValue(0);
    }

    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        pgbPercent = new javax.swing.JProgressBar();
        btnOpenFile = new javax.swing.JButton();
        btnSovle = new javax.swing.JButton();
        btnPause = new javax.swing.JButton();
        btnExit = new javax.swing.JButton();
        lblMaxAge = new javax.swing.JLabel();
        txtMaxAge = new javax.swing.JTextField();
        lblPopulation = new javax.swing.JLabel();
        txtPopulation = new javax.swing.JTextField();
        lblPc = new javax.swing.JLabel();
        txtPc = new javax.swing.JTextField();
        lblPm = new javax.swing.JLabel();
        txtPm = new javax.swing.JTextField();
        lblChooseCrossOver = new javax.swing.JLabel();
        cbbChooseCrossOver = new javax.swing.JComboBox();
        lblChooseMutation = new javax.swing.JLabel();
        cbbChooseMutation = new javax.swing.JComboBox();
        scpInput = new javax.swing.JScrollPane();
        etpInput = new javax.swing.JEditorPane();
        lblInput = new javax.swing.JLabel();
        lblResult = new javax.swing.JLabel();
        scpResult = new javax.swing.JScrollPane();
        tarResult = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Giải hệ phương trình");
        setName("mainFrame");
        setResizable(false);

        btnOpenFile.setText("Mở file");
        btnOpenFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnOpenFileActionPerformed(evt);
            }
        });

        btnSovle.setText("Giải");
        btnSovle.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSovleActionPerformed(evt);
            }
        });

        btnPause.setText("Dừng");
        btnPause.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnPauseActionPerformed(evt);
            }
        });

        btnExit.setText("Thoát");
        btnExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnExitActionPerformed(evt);
            }
        });

        lblMaxAge.setText("Số thế hệ :");

        txtMaxAge.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                txtMaxAgeFocusLost(evt);
            }
        });

        lblPopulation.setText("Dân số :");

        txtPopulation.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                txtPopulationFocusLost(evt);
            }
        });

        lblPc.setText("Xác xuất lai :");

        txtPc.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                txtPcFocusLost(evt);
            }
        });

        lblPm.setText("Xác suất đột biến : ");

        txtPm.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                txtPmFocusLost(evt);
            }
        });

        lblChooseCrossOver.setText("Phép lai :");

        cbbChooseCrossOver.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Simple CrossOver", "Arthmetic CrossOver" }));
        cbbChooseCrossOver.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbbChooseCrossOverActionPerformed(evt);
            }
        });

        lblChooseMutation.setText("Phép đột biến :");

        cbbChooseMutation.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Simple Mutation", "Unsynchronize Mutation" }));
        cbbChooseMutation.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbbChooseMutationActionPerformed(evt);
            }
        });

        scpInput.setViewportView(etpInput);

        lblInput.setText("Đầu vào :");

        lblResult.setText("Kết quả :");

        tarResult.setColumns(20);
        tarResult.setRows(5);
        scpResult.setViewportView(tarResult);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(51, 51, 51)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(lblResult)
                    .addComponent(lblInput)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(btnOpenFile)
                        .addGap(18, 18, 18)
                        .addComponent(btnSovle, javax.swing.GroupLayout.PREFERRED_SIZE, 104, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(btnPause, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addComponent(btnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(pgbPercent, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblChooseCrossOver)
                                .addGap(18, 18, 18)
                                .addComponent(cbbChooseCrossOver, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblMaxAge)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(txtMaxAge, javax.swing.GroupLayout.PREFERRED_SIZE, 51, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addComponent(lblPopulation)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(txtPopulation, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblPc)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(txtPc, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addComponent(lblPm))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblChooseMutation)
                                .addGap(41, 41, 41)
                                .addComponent(cbbChooseMutation, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txtPm, javax.swing.GroupLayout.PREFERRED_SIZE, 68, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(scpResult)
                    .addComponent(scpInput, javax.swing.GroupLayout.Alignment.TRAILING))
                .addContainerGap(51, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(17, 17, 17)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblMaxAge)
                    .addComponent(txtMaxAge, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblPopulation)
                    .addComponent(txtPopulation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblPc)
                    .addComponent(txtPc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblPm)
                    .addComponent(txtPm, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblChooseCrossOver)
                    .addComponent(cbbChooseCrossOver, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblChooseMutation)
                    .addComponent(cbbChooseMutation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(lblInput)
                .addGap(6, 6, 6)
                .addComponent(scpInput, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(lblResult)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(scpResult, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(pgbPercent, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(11, 11, 11)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnOpenFile)
                    .addComponent(btnSovle)
                    .addComponent(btnPause)
                    .addComponent(btnExit))
                .addGap(28, 28, 28))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void btnExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExitActionPerformed
        System.exit(0);
    }//GEN-LAST:event_btnExitActionPerformed

    private void txtMaxAgeFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtMaxAgeFocusLost
        try {
            config.setMaxAge(Integer.parseInt(txtMaxAge.getText()));
            pgbPercent.setMaximum(config.getMaxAge());
        } catch (NumberFormatException e) {
            txtMaxAge.setText(config.getMaxAge() + "");
        }
    }//GEN-LAST:event_txtMaxAgeFocusLost

    private void txtPopulationFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPopulationFocusLost
        try {
            config.setPopulation(Integer.parseInt(txtPopulation.getText()));
        } catch (NumberFormatException e) {
            txtPopulation.setText(config.getPopulation() + "");
        }
    }//GEN-LAST:event_txtPopulationFocusLost

    private void txtPcFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPcFocusLost
        try {
            config.setPc(Double.parseDouble(txtPc.getText()));
        } catch (NumberFormatException e) {
            txtPc.setText(config.getPc() + "");
        }
    }//GEN-LAST:event_txtPcFocusLost

    private void txtPmFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txtPmFocusLost
        try {
            config.setPm(Double.parseDouble(txtPm.getText()));
        } catch (NumberFormatException e) {
            txtPm.setText(config.getPm() + "");
        }
    }//GEN-LAST:event_txtPmFocusLost

    private void cbbChooseCrossOverActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbbChooseCrossOverActionPerformed
        config.setTypeCrossOver(cbbChooseCrossOver.getSelectedIndex());
    }//GEN-LAST:event_cbbChooseCrossOverActionPerformed

    private void cbbChooseMutationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbbChooseMutationActionPerformed
        config.setTypeMutation(cbbChooseMutation.getSelectedIndex());
        Population.setTypeMutation(cbbChooseMutation.getSelectedIndex());
    }//GEN-LAST:event_cbbChooseMutationActionPerformed

    private void btnOpenFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOpenFileActionPerformed
        // Mo Dialog de chon file
        JFileChooser fileChooser = new JFileChooser("C:\\Users\\Khanh\\Desktop");
 //       JFileChooser fileChooser = new JFileChooser(config.getCurrentDirectory());
        int r = fileChooser.showOpenDialog(this);
        if (r == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            config.setCurrentDirectory(fileChooser.getCurrentDirectory());

            // Doc noi dung file hien thi len JEditorPane etpInput
            try {
                etpInput.read(new FileInputStream(file), null);
            } catch (IOException ex) {
                etpInput.setText("");
            }
        }
    }//GEN-LAST:event_btnOpenFileActionPerformed

    private void btnSovleActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSovleActionPerformed
        // Đang giải mà click hủy giải, kết thúc không bình thường, hiển thị kết quả
        if (isSolving) {
            initFrame();
            btnSovle.setText("giải");
            btnPause.setText("dừng");
            return;
        } else {
            isSolving = true;
            btnSovle.setText("hủy giải");
        }

        // Nhan thong tin configure tu mainFrame
        try {
            config.readInput(etpInput.getText());
        } catch (IllegalInputException e) {
            JOptionPane.showMessageDialog(this, "Input không hợp lệ");
            return;
        }

        // Sau khi co thong tin cofigure, bat dau tao Quan the, 
        population = new Population(config);

        // Tien hanh chuong trinh tien hoa trong mot luong moi
        Thread t = new Thread() {

            @Override
            public void run() {
                int dem = 0;
                Chromo bestPre;
                
                startTime = System.nanoTime();
                tarResult.setText("");
                isRunning = true;

                population.init();
                
                bestPre = population.getBestChromo();

                while (population.getAge() < population.getMaxAge() && isSolving) {
                    if (isRunning) {
                        realTime = System.nanoTime() - startTime + offset;
                        
                        // Hien thi progressBar
                        pgbPercent.setValue(population.getAge());
                        
                        population.display();
                        
                        population.crossOver();
                        population.mutation();
                        population.selection();

                        printResult();
                        
                        if(population.getBestChromo() == bestPre){
                            float bestValue = bestPre.maxAbs();
                            dem++;
                            if(dem > 50){
                                if(bestValue < threshold && doxet){
                                    //  Dang trong giai doan doxet truoc khi thu hep khoang nghiem
                                    System.out.println("Be tac, thu hep doan tim nghiem, Khoi tao lai quan the");
                                    population.thayDoiDoanNghiem();
                                    population.init();
                                    doxet = false;
                                }
                                
                                if(population.getAge() > 0.8*population.getMaxAge() && !nuocrut){
                                     population.setPm(0.2);
                                     nuocrut = true;
                                }
                                dem = 0;
                            }
                        }else {
                            bestPre = population.getBestChromo();
                        }
                    
                        population.increaseAge();
                    } else {
                    }
                }

                // Kết thúc quá trình giải một cách bình thường, hiển thị kết quả
                isSolving = false;
                btnSovle.setText("giải");
                
            }
        };
        //EventQueue.invokeLater(t);
        t.start();

    }//GEN-LAST:event_btnSovleActionPerformed

    protected void printResult() {
        StringBuilder result = new StringBuilder();
        result.append("Tuoi : ").append(population.getAge()).append("\n");
        result.append("Kết quả tốt nhất :").append(population.getBestChromo()).append("\n");
        result.append("Gia tri tuyet doi max : ").append(1/population.getBestChromo().value() - 1).append("\n");
        result.append("Thời gian chạy : ").append(realTime / 1000000000).append("s");
        tarResult.setText(result.toString());
    }

    private void btnPauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPauseActionPerformed
        if (isSolving) {
            if (isRunning) {
                btnPause.setText("Tiếp tục");
                isRunning = false;
                offset = realTime;
            } else {
                btnPause.setText("dừng");
                isRunning = true;
                tarResult.setText("");
                startTime = System.nanoTime();
            }
        }
    }//GEN-LAST:event_btnPauseActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnExit;
    private javax.swing.JButton btnOpenFile;
    private javax.swing.JButton btnPause;
    private javax.swing.JButton btnSovle;
    private javax.swing.JComboBox cbbChooseCrossOver;
    private javax.swing.JComboBox cbbChooseMutation;
    private javax.swing.JEditorPane etpInput;
    private javax.swing.JLabel lblChooseCrossOver;
    private javax.swing.JLabel lblChooseMutation;
    private javax.swing.JLabel lblInput;
    private javax.swing.JLabel lblMaxAge;
    private javax.swing.JLabel lblPc;
    private javax.swing.JLabel lblPm;
    private javax.swing.JLabel lblPopulation;
    private javax.swing.JLabel lblResult;
    private javax.swing.JProgressBar pgbPercent;
    private javax.swing.JScrollPane scpInput;
    private javax.swing.JScrollPane scpResult;
    private javax.swing.JTextArea tarResult;
    private javax.swing.JTextField txtMaxAge;
    private javax.swing.JTextField txtPc;
    private javax.swing.JTextField txtPm;
    private javax.swing.JTextField txtPopulation;
    // End of variables declaration//GEN-END:variables

    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }

        MainFrame mainframe = new MainFrame();
        mainframe.setVisible(true);
    }
}
